package com.plentitude.easytrader.provider;


import android.app.Activity;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import com.plentitude.easytrader.provider.WatchlistContract.Quotes;
import com.plentitude.easytrader.provider.WatchlistContract.SearchSuggest;
import com.plentitude.easytrader.provider.WatchlistDatabase.Tables;
import com.plentitude.easytrader.ui.ETApplication;
import com.plentitude.easytrader.util.SelectionBuilder;


/**
 * Provider that stores {@link WatchlistContract} data. Data is usually inserted
 * by {@link SyncService}, and queried by various {@link Activity} instances.
 *
 * @author team@getstarted.com.ua
 */
public class WatchlistProvider extends ContentProvider {
    private static final String TAG = "WatchlistProvider";
    private static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
    private WatchlistDatabase mOpenHelper;
    private static final UriMatcher sUriMatcher = buildUriMatcher();

    private static final int QUOTES = 100;
    private static final int QUOTES_SEARCH = 200;
    private static final int SEARCH_SUGGEST = 300;
    
    /**
     * Build and return a {@link UriMatcher} that catches all {@link Uri}
     * variations supported by this {@link ContentProvider}.
     */
    private static UriMatcher buildUriMatcher() {
        final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        final String authority = WatchlistContract.CONTENT_AUTHORITY;

        matcher.addURI(authority, "quotes", QUOTES);
        matcher.addURI(authority, "quotes/search/*", QUOTES_SEARCH);
        matcher.addURI(authority, "search_suggest_query", SEARCH_SUGGEST);
        return matcher;
    }

    private static final String DATABASE_NAME = "easytrader.db";
    @Override
    public boolean onCreate() {
        final Context context = getContext();
        
        if(ETApplication.USE_SD) {
	        // remove in memory db if exists
        	/*try {
				File old = getContext().getDatabasePath(DATABASE_NAME);
				SQLiteDatabase.openDatabase(old.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY);
		        old.delete(); // delete old instance to recreate db on sdcard
		    } catch (Exception e) { // database doesn't exist yet.
		    	Log.d(TAG, e.toString());
		    }*/
       
		    File preparedDir = new File(ETApplication.CACHE_DIR);
            if(!preparedDir.exists()) {
            	preparedDir.mkdirs();
            }
            mOpenHelper = new WatchlistDatabase(new CustomContext(context), preparedDir.getAbsolutePath() + "/" + DATABASE_NAME);
        } else {
	        mOpenHelper = new WatchlistDatabase(context, DATABASE_NAME);
        }
        return true;
    }
    
    /** {@inheritDoc} */
    @Override
    public String getType(Uri uri) {
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case QUOTES:
                return Quotes.CONTENT_TYPE;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    /** {@inheritDoc} */
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        if (LOGV) Log.v(TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();

        final int match = sUriMatcher.match(uri);
        switch (match) {
            default: {
                // Most cases are handled with simple SelectionBuilder
                final SelectionBuilder builder = buildExpandedSelection(uri, match);
                return builder.where(selection, selectionArgs).query(db, projection, sortOrder);
            }
            case SEARCH_SUGGEST: {
                final SelectionBuilder builder = new SelectionBuilder();

                // Adjust incoming query to become SQL text match
                selectionArgs[0] = selectionArgs[0] + "%";
                builder.table(Tables.SEARCH_SUGGEST);
                builder.where(selection, selectionArgs);
                builder.map(SearchManager.SUGGEST_COLUMN_QUERY, SearchManager.SUGGEST_COLUMN_TEXT_1);
                projection = new String[] { BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_QUERY };
                final String limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT);
                return builder.query(db, projection, null, null, SearchSuggest.DEFAULT_SORT, limit);
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        if (LOGV) Log.v(TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case SEARCH_SUGGEST: {
                db.insertOrThrow(Tables.SEARCH_SUGGEST, null, values);
                return SearchSuggest.CONTENT_URI;
            }
            default: {
                throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        Log.d(TAG, "update(uri=" + uri + ", values=" + values.toString() + ")");
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final SelectionBuilder builder = buildSimpleSelection(uri);
        return builder.where(selection, selectionArgs).update(db, values);
    }

    /** {@inheritDoc} */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        if (LOGV) Log.v(TAG, "delete(uri=" + uri + ")");
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final SelectionBuilder builder = buildSimpleSelection(uri);
        return builder.where(selection, selectionArgs).delete(db);
    }

    /**
     * Apply the given set of {@link ContentProviderOperation}, executing inside
     * a {@link SQLiteDatabase} transaction. All changes will be rolled back if
     * any single one fails.
     */
    /*@Override
    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
            throws OperationApplicationException {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        db.beginTransaction();
        try {
            final int numOperations = operations.size();
            final ContentProviderResult[] results = new ContentProviderResult[numOperations];
            for (int i = 0; i < numOperations; i++) {
                results[i] = operations.get(i).apply(this, results, i);
            }
            db.setTransactionSuccessful();
            return results;
        } finally {
            db.endTransaction();
        }
    }*/

    /**
     * Build a simple {@link SelectionBuilder} to match the requested
     * {@link Uri}. This is usually enough to support {@link #insert},
     * {@link #update}, and {@link #delete} operations.
     */
    private SelectionBuilder buildSimpleSelection(Uri uri) {
        final SelectionBuilder builder = new SelectionBuilder();
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case QUOTES: {
                return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic");
            }
            case SEARCH_SUGGEST: {
                return builder.table(Tables.SEARCH_SUGGEST);
            }
            default: {
                throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    }

    /**
     * Build an advanced {@link SelectionBuilder} to match the requested
     * {@link Uri}. This is usually only used by {@link #query}, since it
     * performs table joins useful for {@link Cursor} data.
     */
    private SelectionBuilder buildExpandedSelection(Uri uri, int match) {
        final SelectionBuilder builder = new SelectionBuilder();
        switch (match) {
            case QUOTES: {
                return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic");
            }
            case QUOTES_SEARCH: {
            	final String filter = Uri.decode(Quotes.getSearchQuery(uri));
            	if("forex".equals(filter)) {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("market like 'FX'");
            	} else if("commodity".equals(filter)) {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("market like 'ETSC'");
            	} else if("stock".equals(filter)) {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("market like 'US' or market like 'UK'");
            	} /*else if("active".equals(filter)) {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("symbol like '" + filter + "%'");
            	} else if("held".equals(filter)) {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("symbol like '" + filter + "%'");
            	}*/ else {
            		return builder.table(Tables.QUOTES + " left join " + Tables.DATA + " on symbol=epic").where("symbol like '" + filter + "%'");
            	}
            }
            default: {
                throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        final int match = sUriMatcher.match(uri);
        switch (match) {
            default: {
                throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    }
    
}
